iT邦幫忙

2022 iThome 鐵人賽

DAY 9
0
DevOps

其實沒有那麼難 — Docker系列 第 9

D9 - 在 Gitlab CICD 使用 Build Cache 加速

  • 分享至 

  • xImage
  •  

我們在 D6 - Build Cache 時,說到了 Docker 可以在建置 Image 時複用已經存在的 Image 來加速,
如果在同一台 Server 上執行建置,很容易就可以觀察並確認 Build Cache 的情況,尤其是當建置需要較長時間時,Build Cache 就起到很大的加速作用,

但如果我們是利用 CICD 工具來執行佈署呢?
CICD 工具每一次都會啟動一個新環境在裡面執行,因此如果用同樣的建置方式放到 CICD 工具上,就會每次都是花費最長的時間,沒有得益於 Build Cache,

於是,我今天的內容就是研究如何在 Gitlab CI 中,依然能透過 Build Cache 得到加速
而為什麼選擇 Gitlab CI,因為目前公司的專案是用 Gitlab CI,我正好能把研究成果用在工作上。


工具介紹

Gitlab CI/CD

Gitlab CI/CD 這套 CICD 工具,可以在 Repo 中透過 YAML 來定義要自動執行的步驟,當我們把程式碼用 git push 推上去到 Gitlab Repo 時,就會自動讀取設定檔開始執行,
對非公開的專案,Gitlab 也有提供免費額度,每個月有固定的分鐘數可以用,因此即使是私人的專案,讀者也可以自己玩玩看。

Gitlab Container Registry

除了 Git Server 以外,Gitlab 也可以用來存放 Docker Image,被稱為 Container Registry,跟 Dockerhub 不一樣的是,Gitlab Container Registry 是以 Gitlab Repo 為單位所提供的服務,

要使用前,需要用 Gitlab 產生的 token 登入,Token 可以是單一 Repo 的 Deploy Token、或是個人的 Personal Access Token

取得 Token 後,使用指令 docker login 來登入,就可以存取 Container Registry。


CICD 流程

接下來說明今天要執行的 CICD 流程,
其中粗體的部分是為了借助 Build Cache 加速而加入的步驟:

  1. 觸發 Gitlab CICD
    對 Repo 的指定分支推送東西 (git push)時,會觸發 CICD
  2. Build image
    1. Gitlab CI 啟動一個新的 Docker 環境
    2. CLI 取得 Gitlab Container Registry 的存取權限
    3. 取得上次建置的 Image
    4. 執行 docker build並加入 --cache-from 參數
    5. 推送新建置的 Image 到 Gitlab Container Registry
  3. 進入 Server 重啟服務
    1. 拉取新的 Image
    2. SSH 進入 Server
    3. 停止並關閉舊的 container
    4. 用新的 Image 重啟服務

Build Cache

D6 中提到,我們可以加入 --cache-from 來明確指定要拿來複用 Cache 的 image,

因此為了加速 CICD 建置 image 的步驟,我們會在 Gitlab CICD 環境中拉取 Container Registry 中的 image,也就是前一次 CICD 推上去的 image,

同樣地,因為這是很小的玩具專案,因此有無 Build Cache 的加速,並不會帶來很大的差異,但是能藉這個玩具來確定自己學會使用它。


實驗與步驟

我們就拿 D5 - Hello World ft. Express 的程式碼來做實驗,第一次的 CICD 執行時會花費完整的時間,

接著我們修改一點點程式碼,加入一支新的 API,確認真的有使用 Build Cache、並成功完成佈署。


Gitlab CICD YAML

接下來就來展示今天的 Gitlab CICD 定義檔,
部分細節可以參考註解上的說明:

## .gitlab-ci.yml

stages:
  - deploy

deploy-dev:
  stage: deploy
  
  # 只有分支 D09/gitlab-ci-build-cache 才會觸發 CICD
  rules:
    - if: '$CI_COMMIT_BRANCH == "D09/gitlab-ci-build-cache"'

  # 指定 Gitlab CICD 要啟動什麼 Image: 使用 Docker Client
  image: docker
  
  # 同時啟動 Docker Daemon 給 Docker Client 使用
  # 可以回想一下 D7 的 Docker 架構圖
  services:
    - docker:dind

  # 在開始前,登入 Gitlab Container Registry
  # 並且放置要 SSH 進入 Server 使用的 Private Key
  before_script:
  # 這幾個環境變數是 Gitlab CICD 預設提供的
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  # 拿取存放在 CICD Variables 的 Private Key 並設置
    - mkdir -p ~/.ssh/
    - echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa

  script:
  # Build docker image
    - cd D05-hello-world-server
	# 一定要先把 image 拉下來,才能作為 Build Cache 使用
	# 同時,最後面加入 `|| true`,確保即使是第一次執行還沒有 image 時,也不會導致 CICD 執行失敗
    - docker pull ${CI_REGISTRY_IMAGE}/hello-world-server || true
	# 以 --cache-from 參數來指定 Build Cache
    - docker build  -t ${CI_REGISTRY_IMAGE}/hello-world-server  .
        --cache-from ${CI_REGISTRY_IMAGE}/hello-world-server
    - docker images
	# 把新的 image 推上去
    - docker push ${CI_REGISTRY_IMAGE}/hello-world-server

  # Deploy
  	# SSH 進入 Server
    - ssh  -tt  -o StrictHostKeyChecking=no ${SERVER_USER}@${SERVER_HOSTNAME} "
		# sudo su 是為了以 root 身分執行指令
        sudo su - -c '
		  # 先拉取 image 再關閉原本的 container,可以減少服務的 down time
          docker pull ${CI_REGISTRY_IMAGE}/hello-world-server &&
          docker stop my-hello-world-server &&
          docker rm my-hello-world-server &&
          docker run  --detach  --publish=3000:3000  --name=my-hello-world-server  ${CI_REGISTRY_IMAGE}/hello-world-server
        '
      "

執行結果

  • 第一次: #3078496874
    (此時 Container Registry 內沒有 image)
$ docker build  -t ${CI_REGISTRY_IMAGE}/hello-world-server  . --cache-from ${CI_REGISTRY_IMAGE}/hello-world-server
Step 1/6 : FROM node:16-slim
16-slim: Pulling from library/node
...
Status: Downloaded newer image for node:16-slim
 ---> 572389d8c38d
Step 2/6 : WORKDIR /app
 ---> Running in b9884f4154fb
Removing intermediate container b9884f4154fb
 ---> 7613e3b5b860
Step 3/6 : COPY ./package*.json ./
 ---> 3bd5adab41ba
Step 4/6 : RUN npm ci
 ---> Running in 19b73e3e7d67
added 57 packages, and audited 58 packages in 1s
7 packages are looking for funding
 ---> ca0edb22da42
Step 5/6 : COPY . .
 ---> 00d80b3a08fa
Step 6/6 : CMD ["npm", "start"]
 ---> Running in 7a9ef41cdbc2
Removing intermediate container 7a9ef41cdbc2
 ---> 0e760d3c7294
Successfully built 0e760d3c7294
Successfully tagged registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:latest
  • 第二次: #3078520292
    印出了 Using cache 的字樣,顯示有使用 Build Cache
$ docker build  -t ${CI_REGISTRY_IMAGE}/hello-world-server  . --cache-from ${CI_REGISTRY_IMAGE}/hello-world-server
Step 1/6 : FROM node:16-slim
16-slim: Pulling from library/node
...
Status: Downloaded newer image for node:16-slim
 ---> 572389d8c38d
Step 2/6 : WORKDIR /app
 ---> Using cache
 ---> 7152da344010
Step 3/6 : COPY ./package*.json ./
 ---> Using cache
 ---> 57221dd03638
Step 4/6 : RUN npm ci
 ---> Using cache
 ---> 786b3ba3622e
Step 5/6 : COPY . .
 ---> 07d4ffad255d
Step 6/6 : CMD ["npm", "start"]
 ---> Running in 430c13426a44
Removing intermediate container 430c13426a44
 ---> 65635b7b8505
Successfully built 65635b7b8505
Successfully tagged registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:latest
  • 呼叫新的 API,確認建置 image 及佈署成功
# On server

$ curl localhost:3000/hola

{"hola":"world"}

以上,就是我今天的研究內容,

本次的程式碼可以在 Gitlab 找到,
Gitlab CICD 執行過程的細節也可以看連結 #3078496874#3078520292

那我們明天再會。


上一篇
D8 - Docker 玩具 — 團隊觀戰區爬蟲
下一篇
D10 - Database by Docker
系列文
其實沒有那麼難 — Docker30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言